﻿#include "sanedeviceoption.h"





SaneOption::SaneOption (QWidget* parent,
                        SANE_Handle handle,
                        int index,
                        const SANE_Option_Descriptor* descr)
    : QWidget (parent)
{
    m_handle = handle;
    m_index = index;
    m_descriptor = descr;
    m_name = m_descriptor->name;
    if (layout () != 0) {
        delete layout ();
    }
    m_layout = new QHBoxLayout (this);
    m_layout->setContentsMargins (5,0,5,0);
    setLayout (m_layout);
    initWidget ();
}
//------------------------------
SaneOption::~SaneOption ()
{
    //	QLayoutItem *child;
    //	while ((child = m_layout->takeAt(0)) != 0) {
    //		delete child;
    //	}
}
//--------------------------------
void SaneOption::initWidget ()
{
    QString t (title ());

    if (!unit ().isEmpty ())
    {
        t = QString ("%1 (%2)")
            .arg (title ())
            .arg (unit ());
    }

    QLabel* label = new QLabel (t, this);
    label->setAlignment (Qt::AlignRight | Qt::AlignVCenter);
    label->setToolTip (description ());
    m_layout->addWidget (label);

    switch (widgetType ())
    {
    case CheckBox:
        {
            m_check = new QCheckBox (this);
            m_layout->addWidget (m_check);
        }
    break;

    case Combo:
        {
            m_combo = new QComboBox (this);
            m_layout->addWidget (m_combo);
        }
    break;

    case Spin:
        {
            m_spin = new QSpinBox (this);
            m_spin->setAccelerated (true);
            m_spin->setButtonSymbols (QAbstractSpinBox::PlusMinus);
            m_layout->addWidget (m_spin);
        }
    break;

    case DoubleSpin:
        {
            m_doubleSpin = new QDoubleSpinBox (this);
            m_doubleSpin->setAccelerated (true);
            m_doubleSpin->setButtonSymbols (QAbstractSpinBox::PlusMinus);
            m_layout->addWidget (m_doubleSpin);
        }
    break;

    case LineEdit:
        {
            m_lineEdit = new QLineEdit (this);
            m_layout->addWidget (m_lineEdit);
        }
    break;

    default:
    break;
    }

    //	m_layout->addStretch ();
    thisWidget ()->setToolTip (description ());
    deviceToGui ();
}
//--------------------------------
void SaneOption::stopSignals ()
{
    thisWidget ()->disconnect ();
}
//---------------------------------
void SaneOption::startSignals ()
{
    switch (widgetType ())
    {
    case CheckBox:
        connect (m_check,
                 SIGNAL(clicked()),
                 this,
                 SLOT(guiToDevice()));
    break;

    case Combo:
        connect (m_combo,
                 SIGNAL(currentIndexChanged(int)),
                 this,
                 SLOT(guiToDevice()));
    break;

    case Spin:
        connect (m_spin,
                 SIGNAL(valueChanged(int)),
                 this,
                 SLOT(guiToDevice()));
    break;

    case DoubleSpin:
        connect (m_doubleSpin,
                 SIGNAL(valueChanged(double)),
                 this,
                 SLOT(guiToDevice()));
    break;

    case LineEdit:
    break;

    default:
    break;
    }
}
//------------------------------------------
SANE_Status SaneOption:: deviceToGui()
{
    //	SANE_Status status = SANE_STATUS_INVAL;

    thisWidget ()->setEnabled (isActive ());

    //----- Déconnexion des SIGNAL-SLOT
    stopSignals ();

    // récupère la valeur donnée par le pilote
    // dans l'interface graphique

    switch (widgetType ())
    {
    case CheckBox:
        m_check->setChecked (deviceValue ().toBool ());
    break;

    case Combo:
        m_combo->clear ();
        foreach (QVariant v, possibleValues ())
        {
            if (valueIsInt ())
                m_combo->addItem (QString ("%1").arg (v.toInt ()));
            if (valueIsDouble ())
                m_combo->addItem (QString ("%1").arg (v.toDouble ()));
            if (valueIsString ())
                m_combo->addItem (QString ("%1").arg (v.toString ()));
        }
        m_combo->setCurrentIndex (m_combo->findText (deviceValue ().toString ()));
    break;

    case Spin:
        {
            QList<QVariant> pv = possibleValues ();
            m_spin->setMinimum (pv [0].toInt ());
            m_spin->setMaximum (pv [1].toInt ());
            m_spin->setValue (deviceValue ().toInt ());
        }
    break;

    case DoubleSpin:
        {
            QList<QVariant> pv = possibleValues ();
            m_doubleSpin->setMinimum ((int) SANE_UNFIX (pv[0].toDouble ()));
            m_doubleSpin->setMaximum ((int) SANE_UNFIX (pv[1].toDouble ()));
            m_doubleSpin->setValue (deviceValue ().toDouble ());
        }
    break;

    case LineEdit:
        m_lineEdit->setText (deviceValue ().toString ());
    break;

    default:
    break;
    }

    //----- Reconnexion des SIGNAL-SLOT
    startSignals ();

    return SANE_STATUS_GOOD;
}
//--------------------------------
const QString SaneOption::guiStrValue ()
{
    if (widgetIsCheckBox ())
        return guiValue ().toBool () ? "yes" : "no";

    return guiValue ().toString ();
}
//--------------------------------
QVariant SaneOption::guiValue ()
{
    switch (widgetType ())
    {
    case CheckBox:
    return m_check->isChecked ();
    break;

    case Combo:
    return m_combo->currentText ();
    break;

    case Spin:
    return m_spin->value ();
    break;

    case DoubleSpin:
    return m_doubleSpin->value ();
    break;

    case LineEdit:
    return m_lineEdit->text ();
    break;

    default:
    return QVariant ();
    break;
    }

    switch (widgetType ())
    {
    case CheckBox:
    break;

    case Combo:
    break;

    case Spin:
    break;

    case DoubleSpin:
    break;

    case LineEdit:
    break;

    default:
    break;
    }

}
//------------------------------------
QVariant SaneOption::deviceValue ()
{
    // retourne la valeur de l'option dans un QVariant
    QVariant result;

    if (valueIsBool ())
    {
        sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, &m_bool, NULL);
        result = (m_bool == SANE_TRUE);
    }
    if (valueIsInt ())
    {
        sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, &m_int, NULL);
        result = m_int;
    }
    if (valueIsDouble ())
    {
        sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, &m_fixed, NULL);
        result = (double) SANE_UNFIX (m_fixed);
    }
    if (valueIsString ())
    {
        sane_control_option (m_handle, m_index, SANE_ACTION_GET_VALUE, &m_string, NULL);
        QString val (m_string);
        result = val;
    }

    return result;
}


//---------------------------------------------------
void SaneOption::setGuiValue (const QString& str)
{
    if (!isActive ()) return;

    switch (widgetType ())
    {
    case CheckBox:
        m_check->setChecked (str == QString ("yes"));
    break;

    case Combo:
        m_combo->setCurrentIndex (m_combo->findText (str));
    break;

    case Spin:
        m_spin->setValue (str.toInt ());
    break;

    case DoubleSpin:
        m_doubleSpin->setValue (str.toDouble ());
    break;

    case LineEdit:
        m_lineEdit->setText (str);
    break;

    default:
    break;
    }
}
//----------------------------------------------
QList<QVariant> SaneOption::possibleValues ()
{
    QList<QVariant> result;

    switch (constraintType ())
    {
    case SANE_CONSTRAINT_RANGE:
        {
            const SANE_Range* range = m_descriptor->constraint.range;
            result << range->min << range->max;
        }
    break;

    case SANE_CONSTRAINT_WORD_LIST:
        {
            const SANE_Word* words = m_descriptor->constraint.word_list;
            for (int index = 1 ; index != words [0] ; index++)
            {
                result << words [index];
            }
        }
    break;

    case SANE_CONSTRAINT_STRING_LIST:
        {
            const SANE_String_Const *list = m_descriptor->constraint.string_list;
            int count = 0;
            while (list [count] != NULL)
            {
                result << list [count];
                count++;
            }
        }
    break;

    default:
    break;
    }

    return result;
}
//----------------------------
QString SaneOption::unit ()
{
    QString result ("");

    switch (m_descriptor->unit)
    {
    case SANE_UNIT_NONE:		/* the value is unit-less (e.g., # of scans) */
    break;

    case SANE_UNIT_PIXEL:		/* value is number of pixels */
        result = QObject::tr ("pixels");
    break;

    case SANE_UNIT_BIT:		/* value is number of bits */
        result = QObject::tr ("bits");
    break;

    case SANE_UNIT_MM:		/* value is millimeters */
        result = QObject::tr ("mm");
    break;

    case SANE_UNIT_DPI:		/* value is resolution in dots/inch */
        result = QObject::tr ("DPI");
    break;

    case SANE_UNIT_PERCENT:		/* value is a percentage */
        result = QObject::tr ("%");
    break;

    case SANE_UNIT_MICROSECOND:	/* value is micro seconds */
        result = QObject::tr ("μs");
    break;
    }

    return result;
}

//--------------------------------------
SANE_Status SaneOption::guiToDevice ()
{
    SANE_Status status = SANE_STATUS_GOOD;
    SANE_Int info;

    if (valueIsBool ())
    {
        m_bool = m_check->isChecked ();
        status = sane_control_option (m_handle, m_index, SANE_ACTION_SET_VALUE, &m_bool, &info);
    }

    if (valueIsInt ())
    {
        m_int = guiValue ().toInt ();
        status = sane_control_option (m_handle, m_index,  SANE_ACTION_SET_VALUE, &m_int, &info);
    }

    if (valueIsDouble ())
    {
        m_fixed = SANE_FIX (guiValue ().toDouble ());
        status = sane_control_option (m_handle, m_index,  SANE_ACTION_SET_VALUE, &m_fixed, &info);
    }

    if (valueIsString ())
    {
        char * from = guiValue ().toString ().toLatin1 ().data ();
        strcpy (m_string, from);
        status = sane_control_option (m_handle, m_index,  SANE_ACTION_SET_VALUE, &m_string, &info);
    }

    if (info & SANE_INFO_RELOAD_OPTIONS)
    {
        emit mustReloadOptions ();
    }

    if (info & SANE_INFO_INEXACT)
    {
        deviceToGui ();
    }


    return status;
}
